/**
 * created at 02.09.2008, 17:10:48
 */
package de.jmda.core.util.jpa;

import javax.lang.model.element.ElementKind;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;

import de.jmda.core.mproc.ProcessingUtilities;

/**
 * Abstract base class for classes that provide information about bidirectional
 * entity relations.
 */
public abstract class EntityRelationInfoBidirectional
extends EntityRelationInfo
{
	protected VariableElement owningField;
	protected VariableElement inverseField;

	/**
	 * Calls {@link
	 * EntityRelationInfo#EntityRelationInfo(EntityRelation, VariableElement)}
	 * (<code>declaredField</code> is used as <code>FieldDeclaration</code>
	 * parameter).
	 * <p>
	 * Stores <code>owningField</code> to {@link
	 * #owningField} and <code>inverseField</code> to {@link
	 * #inverseField}.
	 *
	 * @param entityRelation
	 * @param declaredField
	 * @param owningField
	 * @param inverseField
	 */
	protected EntityRelationInfoBidirectional(
			EntityRelation entityRelation,
			VariableElement declaredField,
			VariableElement owningField,
			VariableElement inverseField)
	{
		super(entityRelation, declaredField);

		if ((owningField.getEnclosingElement().getKind() == ElementKind.CLASS) ==
				false)
		{
			throw new IllegalArgumentException(
					"owningField has to be declared in a class declaration");
		}
		else
		{
			this.owningField = owningField;
		}

		if ((inverseField.getEnclosingElement().getKind() == ElementKind.CLASS) ==
				false)
		{
			throw new IllegalArgumentException(
					"inverseField has to be declared in a class declaration");
		}
		else
		{
			this.inverseField = inverseField;
		}
	}

	/**
	 * @see de.jmda.core.util.jpa.EntityRelationInfo#getOwningField()
	 */
	@Override
	public VariableElement getOwningField()
	{
		return owningField;
	}

	/**
	 * According to JSR-220 (EJB 3.0 specification) JPA, chapter 2.1.7 every
	 * <b>bidirectional</b> entity relation has an owning side (see {@link
	 * #getOwningField()}) and an inverse side.
	 *
	 * @return declaredField declaration of the inverse declaredField in a bidirectional entity
	 *         relation
	 */
	public VariableElement getInverseField()
	{
		return inverseField;
	}

	public DeclaredType getDeclaredTypeOwningField()
	{
		return ProcessingUtilities.asDeclaredType(owningField.asType());
	}

	public DeclaredType getDeclaredTypeInverseField()
	{
		return ProcessingUtilities.asDeclaredType(inverseField.asType());
	}

	public VariableElement getRelatedFieldDeclaration()
	{
		if (owningField.equals(declaredField))
		{
			return inverseField;
		}

		return owningField;
	}

	/**
	 * @see de.jmda.core.util.jpa.EntityRelationInfo#toString()
	 */
	@Override
	public String toString()
	{
		return
				super.toString() + "\n" +
				"owning declaredField   [" + owningField.asType()  + "." + owningField.getSimpleName()  + "]\n" +
				"inverse declaredField  [" + inverseField.asType() + "." + inverseField.getSimpleName() + "]";
	}
}